﻿using System;
using System.IO.Ports;

namespace ROVController
{
	public enum PacketType
	{
		ControlROV,
		RequestVersions,
		ResetPolyBot
	}

	public struct VersionInfo
	{
		public string ROVSoftwareVersion;
		public string AvrLibcVersion;
		public string AvrLibcDate;
	}

	public class ROV
	{
		//Constants
		private const int NUM_TORPEDOES = 3;

		//Member variables
		PacketAPI packetAPI;
		private byte torpedoStates = 0;

		//Constructor
		public ROV(SerialPort serialPort)
		{
			packetAPI = new PacketAPI(serialPort);
		}

		#region Properties
		private byte leftThruster = 127;
		public byte LeftThruster
		{
			set
			{
				leftThruster = value;
			}
			get
			{
				return leftThruster;
			}
		}

		private byte rightThruster = 127;
		public byte RightThruster
		{
			set
			{
				rightThruster = value;
			}
			get
			{
				return rightThruster;
			}
		}

		private byte verticalThruster = 127;
		public byte VerticalThruster
		{
			set
			{
				verticalThruster = value;
			}
			get
			{
				return verticalThruster;
			}
		}

		private byte sideThruster = 127;
		public byte SideThruster
		{
			set
			{
				sideThruster = value;
			}
			get
			{
				return sideThruster;
			}
		}

		private byte cameraTilt = 127;
		public byte CameraTilt
		{
			set
			{
				cameraTilt = value;
			}
			get
			{
				return cameraTilt;
			}
		}

		private byte armWrist = 127;
		public byte ArmWrist
		{
			set
			{
				armWrist = value;
			}
			get
			{
				return armWrist;
			}
		}

		private byte gripper = 0;
		public byte Gripper
		{
			set
			{
				gripper = value;
			}
			get
			{
				return gripper;
			}
		}

		private byte lightBrightness = 0;
		public byte LightBrightness
		{
			set
			{
				if (value > 100)
				{
					throw new ArgumentOutOfRangeException(null, "LightBrightness must not exceed 100");
				}
				lightBrightness = value;
			}
			get
			{
				return lightBrightness;
			}
		}
		#endregion


		/// <summary>
		/// Fires the specified torpedo.
		/// </summary>
		/// <param name="torpedoNumber">The torpedo number. Can be 1 to NUM_TORPEDOES.</param>
		public void FireTorpedo(int torpedoNumber)
		{
			if (torpedoNumber < 1 || torpedoNumber > NUM_TORPEDOES)
			{
				throw new ArgumentOutOfRangeException("torpedoNumber", "torpedoNumber must be an int in the range 1-" + NUM_TORPEDOES);
			}
			torpedoStates |= (byte)(1 << (torpedoNumber - 1));
		}

		/// <summary>
		/// Resets the torpedo states, allowing them to be reloaded.
		/// </summary>
		public void ResetTorpedoStates()
		{
			torpedoStates = 0;
		}

		/// <summary>
		/// Sends a control packet to the ROV containing values for all outputs.
		/// </summary>
		/// <returns>The sequence number that the packet was sent with.</returns>
		public byte ControlROV()
		{
			byte[] packetData = new byte[] { leftThruster, rightThruster, verticalThruster, sideThruster, cameraTilt, armWrist, gripper, torpedoStates, lightBrightness };
			return packetAPI.sendPacket(PacketType.ControlROV, packetData);
		}

		/// <summary>
		/// Requests version information from the microcontroller.
		/// </summary>
		/// <returns>The sequence number that the packet was sent with.</returns>
		public byte RequestVersions()
		{
			return packetAPI.sendPacket(PacketType.RequestVersions);
		}

		/// <summary>
		/// Commands the PolyBot Board to reset itself using the watchdog timer and an infinite loop.
		/// This software reset is similar to a hardware reset.
		/// The board will reset and run the bootloader, so this could be used to allow re-programming.
		/// The microcontroller code shall first halt all motors/servos for safety.
		/// </summary>
		/// <returns>The sequence number that the packet was sent with.</returns>
		public byte ResetPolyBot()
		{
			return packetAPI.sendPacket(PacketType.ResetPolyBot);
		}
	}
}
